package com.allesblinkt.mucom.client;

import java.awt.AWTException;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.util.Vector;

import processing.core.PApplet;
import processing.core.PImage;

import com.allesblinkt.mucom.common.Constants;

import mathematik.Vector2f;

public class ScreenTiler implements Runnable, Constants {

	private Thread runner;

	private ClientApp app;

	private boolean running = true;

	private ScreenTile[][] tiles;

	private int xRes;

	private int yRes;

	private Vector<ScreenTile> currentlyAffectedTiles;

	private long lastTickle;

	public ScreenTiler(ClientApp theApp) {

		app = theApp;

		xRes = PApplet.ceil(app.screen.width / (float) TILE_WIDTH);
		yRes = PApplet.ceil(app.screen.height / (float) TILE_HEIGHT);

		tiles = new ScreenTile[xRes][yRes];

		currentlyAffectedTiles = new Vector<ScreenTile>();

		init();
		
		tickle();
		
		runner = new Thread(this);
		runner.setDaemon(true);
		runner.start();

	}

	private void init() {
		for (int ix = 0; ix < xRes; ix++) {
			for (int iy = 0; iy < yRes; iy++) {

				BufferedImage capture = getScreenShot(ix, iy);
				PImage pimage = new PImage(capture);

				if (pimage != null) {
					tiles[ix][iy] = new ScreenTile(pimage, screenX(ix),
							screenY(iy));

				}
			}
		}
	}

	private int screenX(int theX) {
		int screenX = theX * TILE_WIDTH;
		return screenX;
	}

	private int screenY(int theY) {
		int screenY = theY * TILE_HEIGHT;
		return screenY;
	}

	private BufferedImage getScreenShot(int theX, int theY) {

		int captureWidth = PApplet.min(TILE_WIDTH, app.screen.width - screenX(theX) );
		int captureHeight = PApplet.min(TILE_HEIGHT, app.screen.height - screenY(theY));
		


		Rectangle rect = new Rectangle(screenX(theX), screenY(theY),
				captureWidth, captureHeight);
		

		BufferedImage capture = null;

		try {
			Robot robot = new Robot();
			capture = robot.createScreenCapture(rect);

		} catch (AWTException e) {
			e.printStackTrace();
		}
		

		return capture;
	}

	private Vector<Point> getAffectedTileIndexes(Vector2f thePosition) {
		int minX = PApplet.max(0, PApplet.floor(thePosition.x / TILE_WIDTH));
		int minY = PApplet.max(0, PApplet.floor(thePosition.y / TILE_HEIGHT));

		int maxX = PApplet.min(xRes, PApplet
				.ceil((thePosition.x + WINDOW_WIDTH) / TILE_WIDTH));
		int maxY = PApplet.min(yRes, PApplet
				.ceil((thePosition.y + WINDOW_HEIGHT) / TILE_HEIGHT));

		Vector<Point> points = new Vector<Point>();

		for (int ix = minX; ix < maxX; ix++) {

			for (int iy = minY; iy < maxY; iy++) {

				points.add(new Point(ix, iy));

			}
		}

		return points;

	}

	public Vector<ScreenTile> get(Vector2f thePosition) {

		Vector<ScreenTile> returnTiles = new Vector<ScreenTile>();

		Vector<Point> thePoints = getAffectedTileIndexes(thePosition);

		for (Point thePoint : thePoints) {
			if (tiles[thePoint.x][thePoint.y] != null) {
				returnTiles.add(tiles[thePoint.x][thePoint.y]);

			}
		}

		currentlyAffectedTiles = returnTiles;

		return returnTiles;
	}

	public void run() {
		while (running) {
			try {
				Thread.sleep(100);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			if(System.currentTimeMillis() - lastTickle > TICKLE_TIMEOUT * 1000){
				running = false;
			}
			
			double time = System.currentTimeMillis();
			for (ScreenTile[] tilesx : tiles) {
				for (ScreenTile tile : tilesx) {
					if (time - tile.age > TILE_LIFESPAN * 1000
							&& !currentlyAffectedTiles.contains(tile)) {

						Rectangle rect = new Rectangle(tile.x, tile.y,
								TILE_WIDTH, TILE_HEIGHT);

						PImage img = null;

						try {
							Robot robot = new Robot();
							BufferedImage capture = robot
									.createScreenCapture(rect);

							if (capture != null)
								img = new PImage(capture);

							tile.age = System.currentTimeMillis();
						} catch (AWTException e) {
							e.printStackTrace();
						}

						if (img != null)
							tile.image = img;

					}
				}
			}
		}
	}

	public void tickle() {
		lastTickle = System.currentTimeMillis();		
	}
}
